package Othello;

import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import java.util.ArrayList;

enum ChessType {
    black, white, blank;

    public ChessType reverse() {
        return this == black ? white : this == white ? black : blank;
    }
}

class Point {
    int x;
    int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

class Cell {
    private ChessType chessType;
    private int x;
    private int y;

    public Cell(int x, int y, ChessType chessType) {
        this.x = x;
        this.y = y;
        this.chessType = chessType;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public ChessType getChessType() {
        return chessType;
    }

    @Override
    public String toString() {

        return "Cell{" +
                "chessType=" + chessType +
                ", x=" + x +
                ", y=" + y +
                '}';

    }
}

enum Direction {
    up(new Point(0, -1)),
    down(new Point(0, 1)),
    left(new Point(-1, 0)),
    right(new Point(1, 0)),
    upLeft(new Point(-1, -1)),
    upRight(new Point(1, -1)),
    downRight(new Point(1, 1)),
    downLeft(new Point(-1, 1));

    private Point p;

    Direction(Point p) {
        this.p = p;
    }

    public Point getP() {
        return p;
    }

}

public class CheckBoard implements Iterable<Cell> {

    private ChessType[][] chessBoard;
    private int max_x;
    private int max_y;

    public CheckBoard(int max_x, int max_y) {
        this.max_x = max_x;
        this.max_y = max_y;
        chessBoard = new ChessType[max_x][max_y];
    }

    public void putChess(int x, int y, ChessType chessType) {
        chessBoard[x][y] = chessType;
    }

    public ChessType getChess(int x, int y) {

        ChessType t = chessBoard[x][y];
        if (t == null)
            return ChessType.blank;
        else
            return t;
    }

    public int getMax_x() {
        return max_x;
    }

    public int getMax_y() {
        return max_y;
    }

    @Override
    public Iterator<Cell> iterator() {
        // 实现Iterator接口，用于遍历棋盘上的每个棋子
        return new Iterator<Cell>() {

            // 初始化棋盘坐标的x轴位置
            private int x = 0;
            // 初始化棋盘坐标的y轴位置
            private int y = 0;

            @Override
            public boolean hasNext() {
                // 判断棋盘上是否有下一个棋子
                return x < getMax_x() && y < getMax_y();
            }

            @Override
            public Cell next() {
                // 获取当前坐标上的棋子，并移动到下一个位置
                Cell cell = new Cell(x, y, getChess(x, y));
                x++; // 在x轴上移动到下一个位置
                if (x >= getMax_x()) {
                    // 如果x轴达到最大值，则重置x轴并移动y轴到下一个位置
                    x = 0;
                    y++;
                }
                return cell;
            }
        };
    }

    public Stream<Cell> stream(Direction dir, Point start) {
        return Stream.iterate(start, p -> new Point(p.getX() + dir.getP().getX(), p.getY() + dir.getP().getY()))
                .map(p -> new Cell(p.getX(), p.getY(), getChess(p.getX(), p.getY())))
                .takeWhile(cell -> cell.getX() < getMax_x() && cell.getY() < getMax_y());
    }

    private <T> Stream<T> iteratorToStream(Iterator<T> iterator) {
        Iterable<T> iterable = () -> iterator;
        return StreamSupport.stream(iterable.spliterator(), false);
    }

    public Stream<Cell> stream() {
        return iteratorToStream(iterator());
    }

    // 从cells中过滤出连续的与给定类型相同的细胞
    public Stream<Cell> getReverseCells(ChessType chessType, Stream<Cell> cells) {
        // 从cells中找到第一个与给定类型不同的细胞
        List<Cell> list = cells.collect(Collectors.toList());
        Cell first = list.stream().filter(c -> c.getChessType() != chessType).findFirst().orElse(null);
        if (first == null)
            return Stream.empty();
        return list.stream().takeWhile(c -> c != first);
    }

    public Stream<Cell> getReverseCells(ChessType chessType, Point point) {
        List<Cell> result = new ArrayList<>();
        for (Direction dir : Direction.values()) {
            List<Cell> directionCells = new ArrayList<>();
            Point current = new Point(
                    point.getX() + dir.getP().getX(),
                    point.getY() + dir.getP().getY());

            while (isWithinBounds(current) && getChess(current.getX(), current.getY()) == chessType.reverse()) {
                directionCells.add(new Cell(current.getX(), current.getY(), chessType.reverse()));
                current = new Point(
                        current.getX() + dir.getP().getX(),
                        current.getY() + dir.getP().getY());
            }

            if (isWithinBounds(current) && getChess(current.getX(), current.getY()) == chessType) {
                result.addAll(directionCells);
            }
        }
        return result.stream();
    }

    private boolean isWithinBounds(Point p) {
        return p.getX() >= 0 && p.getX() < max_x && p.getY() >= 0 && p.getY() < max_y;
    }

    public void putChess(Point point, ChessType chessType) {
        putChess(point.getX(), point.getY(), chessType);

        getReverseCells(chessType, point).forEach(cell -> {
            System.out.println(cell);
            putChess(cell.getX(), cell.getY(), chessType.reverse());
        });
    }

    public boolean isValidMove(Point point, ChessType chessType) {
        if (getChess(point.getX(), point.getY()) != ChessType.blank) {
            return false;
        }

        for (Direction dir : Direction.values()) {
            Point current = new Point(
                    point.getX() + dir.getP().getX(),
                    point.getY() + dir.getP().getY());

            boolean foundOpponent = false;
            while (isWithinBounds(current) && getChess(current.getX(), current.getY()) == chessType.reverse()) {
                foundOpponent = true;
                current = new Point(
                        current.getX() + dir.getP().getX(),
                        current.getY() + dir.getP().getY());
            }

            if (foundOpponent && isWithinBounds(current) && getChess(current.getX(), current.getY()) == chessType) {
                return true;
            }
        }
        return false;
    }

}

// 使用一个二维的字符串模拟一个屏幕
class Screen {

    private String[] screen;

    public Screen(int width, int height) {
        screen = new String[height];
        for (int i = 0; i < height; i++)
            screen[i] = " ".repeat(width);
    }

    public void setAt(int x, int y, Character c) {
        screen[y] = screen[y].substring(0, x) + c + screen[y].substring(x + 1);
    }

    void print() {
        for (String line : screen)
            if (!line.isEmpty())
                System.out.println(line);
    }
}
